/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2021-11-15     Eywen       the first version
 */

#include "files.h"

/* 遍历当前路径，统计文件的个数  */
int get_files_count(const char *pathname)
{
    struct stat stat;
    int length;
    char *fullpath, *path;
    int files = 0;
    struct dfs_fd fd;
    struct dirent dirent;

    fullpath = NULL;
    if (pathname == NULL){
#ifdef DFS_USING_WORKDIR
        /* open current working directory */
        path = rt_strdup(working_directory);
#else
        path = rt_strdup("/");
#endif
        if (path == NULL)
            return files; /* out of memory */
    }
    else{
        path = (char *)pathname;
    }

    /* list directory */
    if (dfs_file_open(&fd, path, O_DIRECTORY) == 0){
        do{
            memset(&dirent, 0, sizeof(struct dirent));
            length = dfs_file_getdents(&fd, &dirent, sizeof(struct dirent));
            if (length > 0){
                memset(&stat, 0, sizeof(struct stat));

                /* build full path for each file */
                fullpath = dfs_normalize_path(path, dirent.d_name);
                if (fullpath == NULL)
                    break;

                if (dfs_file_stat(fullpath, &stat) == 0){
                    //rt_kprintf("%-20s", dirent.d_name);
                    if (S_ISDIR(stat.st_mode) == false){
                        files++;
                    }
                }
                else{
                    rt_kprintf("BAD file: %s\n", dirent.d_name);
                }
                rt_free(fullpath);
            }
        }while (length > 0);
        dfs_file_close(&fd);
    }
    else{
        rt_kprintf("No such directory\n");
    }
    if (pathname == NULL){
        rt_free(path);
    }
    return files;
}

typedef struct dir_file_des{
    char **file_list;
    int select_idx;
    int write_idx;
    int size;
}dir_file_des_t;

static dir_file_des_t s_dir_file_des;

static void dif_file_des_free(dir_file_des_t *des)
{
    ASSERT_NULL(des);
    for(int i = 0; i < des->size; i++){
        MEM_FREE(des->file_list[i]);
        des->file_list[i] = NULL;
    }
    MEM_FREE(des->file_list);
    //des->select_idx = 0;
    des->write_idx = 0;
    des->size = 0;
}

char *get_select_file_name(void)
{
    if(s_dir_file_des.size > 0){
        if((s_dir_file_des.select_idx < 0) ||
                (s_dir_file_des.select_idx >= s_dir_file_des.size)){
            s_dir_file_des.select_idx = 0;
        }
        return s_dir_file_des.file_list[s_dir_file_des.select_idx];
    }
    else{
        return NULL;
    }

}

static bool dif_file_des_init(dir_file_des_t *des, int size)
{
    ASSERT_NULL(des);
    des->file_list = MEM_MALLOC(sizeof(char *)*size);
    if(NULL == des->file_list){
        return false;
    }
    memset(des->file_list, 0, sizeof(char *)*size);
    //des->select_idx = 0;
    des->write_idx = 0;
    des->size = size;
    return true;
}

static bool dif_file_des_append(dir_file_des_t *des, char *file_name)
{
    ASSERT_NULL(des);
    //debug_info("append: %d %s %d", des->write_idx, file_name, des->size);
    if(des->write_idx >= des->size){
        return false;
    }
    des->file_list[des->write_idx] = MEM_MALLOC(strlen(file_name) + 1);

    if(NULL == des->file_list[des->write_idx] ){
        return false;
    }
    memcpy(des->file_list[des->write_idx++], file_name, strlen(file_name));
    return true;
}

char *get_cur_dif_file_name(int idx)
{
    if(idx >= s_dir_file_des.size){
        debug_warn("file idx err");
    }
    s_dir_file_des.select_idx = idx;
    //s_dir_file_des.select_idx = idx;
    return s_dir_file_des.file_list[idx];
}

int refresh_file_names(const char *pathname)
{
    int file_count;
    file_count = get_files_count(pathname);
    dif_file_des_free(&s_dir_file_des);
    dif_file_des_init(&s_dir_file_des, file_count);

    struct stat stat;
    int length;
    char *fullpath, *path;
    int files = 0;
    struct dfs_fd fd;
    struct dirent dirent;

    fullpath = NULL;
    if (pathname == NULL){
#ifdef DFS_USING_WORKDIR
        /* open current working directory */
        path = rt_strdup(working_directory);
#else
        path = rt_strdup("/");
#endif
        if (path == NULL)
            return ; /* out of memory */
    }
    else{
        path = (char *)pathname;
    }

    /* list directory */
    if (dfs_file_open(&fd, path, O_DIRECTORY) == 0){
        do{
            memset(&dirent, 0, sizeof(struct dirent));
            length = dfs_file_getdents(&fd, &dirent, sizeof(struct dirent));
            if (length > 0){
                memset(&stat, 0, sizeof(struct stat));

                /* build full path for each file */
                fullpath = dfs_normalize_path(path, dirent.d_name);
                if (fullpath == NULL)
                    break;

                if (dfs_file_stat(fullpath, &stat) == 0){
                    //rt_kprintf("%-20s", dirent.d_name);
                    if (S_ISDIR(stat.st_mode) == false){
                        dif_file_des_append(&s_dir_file_des, fullpath);
                    }
                }
                else{
                    rt_kprintf("BAD file: %s\n", dirent.d_name);
                }
                rt_free(fullpath);
            }
        }while (length > 0);
        dfs_file_close(&fd);
    }
    else{
        rt_kprintf("No such directory\n");
    }
    if (pathname == NULL){
        rt_free(path);
    }
    return file_count;
}

void list_cur_dir_files(const char *pathname)
{
    refresh_file_names(pathname);
    for(int i = 0; i < s_dir_file_des.size; i++){
        debug_info("%d %s", i, s_dir_file_des.file_list[i]);
    }
}

int get_cur_dir_file_cnt(void)
{
    return s_dir_file_des.size;
}

int get_file_data(char *file_name, uint8_t *save, int len)
{
    static struct dfs_fd s_fd;
    static char *file_name_save = NULL;

    ASSERT_NULL(save);

    if(file_name == NULL){
        return -1;
    }

    if(file_name_save != file_name){
        if(file_name_save != NULL){
            dfs_file_close(&s_fd);
            file_name_save = NULL;
        }
        if(dfs_file_open(&s_fd, file_name, O_RDONLY) < 0){
            debug_info("open file %s error", get_cur_dif_file_name(0));
            return -1;
        }
        file_name_save = file_name;
    }
    len = dfs_file_read(&s_fd, save, len);
    /* 读取完毕或错误 */
    if(len <= 0){
        dfs_file_close(&s_fd);
        file_name_save = NULL;
    }
    return len;
}

int get_line_gcoode_from_file(const char *file_name, uint8_t *save)
{
    static struct dfs_fd s_fd;
    static char *file_name_save = NULL;

    ASSERT_NULL(save);

    if(file_name == NULL){
        return -1;
    }

    if(file_name_save != file_name){
        if(file_name_save != NULL){
            dfs_file_close(&s_fd);
            file_name_save = NULL;
        }
        if(dfs_file_open(&s_fd, file_name, O_RDONLY) < 0){
            debug_info("open file %s error", get_cur_dif_file_name(0));
            return -1;
        }
        file_name_save = (char *)file_name;
    }
    int len = 0;
    char ch;
    do{
        if(1 == dfs_file_read(&s_fd, &ch, 1)){
            save[len++] = ch;
        }
        /* 文件读取完毕 */
        else{
            dfs_file_close(&s_fd);
            file_name_save = NULL;
            return len;
        }
    }while('\n' != ch);
    save[len] = '\0';

    /* 读取完毕或错误 */
    if(len <= 0){
        dfs_file_close(&s_fd);
        file_name_save = NULL;
    }
    return len;
}
